/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.thingsgrid.workorder.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Maps;
import com.thingsgrid.desk.vo.NoticeVO;
import com.thingsgrid.workorder.entity.ProcessWorkOrder;
import com.thingsgrid.workorder.entity.Record;
import com.thingsgrid.workorder.mapper.WorkOrderMapper;
import com.thingsgrid.flow.core.constant.ProcessConstant;
import com.thingsgrid.flow.core.entity.BladeFlow;
import com.thingsgrid.flow.core.feign.IFlowClient;
import com.thingsgrid.flow.core.utils.FlowUtil;
import com.thingsgrid.flow.core.utils.TaskUtil;
import com.thingsgrid.workorder.service.IWorkOrderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.mp.support.BladePage;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 服务实现类
 *
 * @author MQ
 */
@Slf4j
@Service
@AllArgsConstructor
public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, ProcessWorkOrder> implements IWorkOrderService {

	private IFlowClient flowClient;
	private final Integer STATUS =  4 ;
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean startProcess(ProcessWorkOrder processWorkOrder) {
		AtomicBoolean temp = new AtomicBoolean(true);
		String businessTable = FlowUtil.getBusinessTable(ProcessConstant.WRMANAGER_KEY);
		if (Func.isEmpty(processWorkOrder.getId())) {
			// 保存leave
			processWorkOrder.setCreateTime(DateUtil.now());
			Map m = baseMapper.findUserGroupByType(processWorkOrder.getOrderType());
			/**
			 * 无分配责任人和工作组对应表，先用分组ID当分配责任人ID
			 */
			String disId = m.get("usr_group").toString();
			processWorkOrder.setOrderOwner(Long.parseLong(disId));
			processWorkOrder.setCreateUser(SecureUtil.getUserId());
			save(processWorkOrder);
			Kv variables = Kv.create().set(ProcessConstant.TASK_VARIABLE_CREATE_USER, SecureUtil.getUserId()).set("disUser", TaskUtil.getTaskUser(String.valueOf(processWorkOrder.getOrderOwner())));
			R<BladeFlow> result = flowClient.startProcessInstanceById(processWorkOrder.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(processWorkOrder.getId())), variables);
			if (result.isSuccess()) {
				log.debug("流程已启动,流程ID:" + result.getData().getProcessInstanceId());
				processWorkOrder.setProcessInstanceId(result.getData().getProcessInstanceId());
				// todo
				List<Record> records = new Record().getRecords(String.valueOf(SecureUtil.getUserId()),String.valueOf(processWorkOrder.getOrderOwner()));
				processWorkOrder.setRecord(JSON.toJSONString(records));

				updateById(processWorkOrder);
			} else {
				throw new ServiceException("创建工单失败");
			}
		} else {
			updateById(processWorkOrder);
		}
		return temp.get();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean disProcess(List<ProcessWorkOrder> processWorkOrders,String targetId) {
		try{
			AtomicBoolean temp = new AtomicBoolean(true);
			processWorkOrders.forEach(v->{
				ProcessWorkOrder pw = baseMapper.findByid(String.valueOf(v.getId()));
				if(pw.getStatus().equals(STATUS)){
					throw new ServiceException("工单已关闭");
				}
				Kv variables = Kv.create().set("handUser", TaskUtil.getTaskUser(targetId));
				R r = flowClient.completeTask(v.getTaskId(),pw.getProcessInstanceId(),"分配工单",variables);
				if(r.isSuccess()){
					List<Record> records = JSON.parseArray(pw.getRecord(),Record.class);
					List<Record> recordsnew = new Record().getRecords(String.valueOf(SecureUtil.getUserId()),targetId);
					records.addAll(recordsnew);
					v.setStatus(1);
					v.setRecord(JSON.toJSONString(records));
				}else{
					throw new ServiceException("分配工单失败");
				}
			});
			baseMapper.updateBatch(processWorkOrders);
			return temp.get();
		}catch (Exception e){
			throw new ServiceException("分配工单失败");
		}
	}
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean handProcess(List<ProcessWorkOrder> processWorkOrders) {
		try{
			AtomicBoolean temp = new AtomicBoolean(true);
			processWorkOrders.forEach(v->{
				ProcessWorkOrder pw = baseMapper.findByid(String.valueOf(v.getId()));
				if(pw.getStatus().equals(STATUS)){
					throw new ServiceException("工单已关闭");
				}
				Kv variables = Kv.create().set("applyUser", TaskUtil.getTaskUser(String.valueOf(pw.getCreateUser())));
				R r = flowClient.completeTask(v.getTaskId(),pw.getProcessInstanceId(),"处理工单",variables);
				if(r.isSuccess()){
					List<Record> records = JSON.parseArray(pw.getRecord(),Record.class);
					List<Record> records1 = new Record().getRecords(String.valueOf(SecureUtil.getUserId()),String.valueOf(pw.getCreateUser()));
					records.addAll(records1);
					v.setRecord(JSON.toJSONString(records));
					v.setStatus(3);
				}else{
					throw new ServiceException("工单处理失败");
				}
			});

			baseMapper.updateBatch(processWorkOrders);
			return temp.get();
		}catch (Exception e){
			throw new ServiceException("工单处理失败");
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean closeProcess(List<ProcessWorkOrder> processWorkOrders) {
		try{
			AtomicBoolean temp = new AtomicBoolean(true);
			processWorkOrders.forEach(v->{
				ProcessWorkOrder pw = baseMapper.findByid(String.valueOf(v.getId()));
				List<Record> records = JSON.parseArray(pw.getRecord(),Record.class);
				List<Record> records1 = new Record().getRecords(String.valueOf(SecureUtil.getUserId()),"over");
				records.addAll(records1);
				v.setStatus(4);
				v.setRecord(JSON.toJSONString(records));
			});
			baseMapper.updateBatch(processWorkOrders);
			return temp.get();
		}catch (Exception e){
			throw new ServiceException("工单关闭失败");
		}
	}

	@Override
	public ProcessWorkOrder getOneWorkOrder(long odrId) {
		return baseMapper.findByid(String.valueOf(odrId));
	}

	/**
	 * 获取工单列表
	 *
	 * @return
	 */
	@Override
	public IPage<ProcessWorkOrder> getListProcessWorkOrders(Query query, ProcessWorkOrder processWorkOrder) {
		List<String> list = new ArrayList<>();
		List<BladeFlow> listBladeFlow = new ArrayList<>();
		List<ProcessWorkOrder> processWorkOrders = new ArrayList<>();
		IPage<ProcessWorkOrder> page = Condition.getPage(query);
		if(StringUtil.isEmpty(processWorkOrder.getStatus())){
			List<ProcessWorkOrder> processWorkOrdersf = listBladeFlowResult(listBladeFlow, query, list,processWorkOrder);
			List<ProcessWorkOrder> processWorkOrdersd  = listBladeFlowResultd(listBladeFlow, query, list,processWorkOrder);
			List<ProcessWorkOrder> processWorkOrderse  = listBladeFlowResulte(listBladeFlow, query, list,processWorkOrder);
			if(processWorkOrdersf != null){
				processWorkOrders.addAll(processWorkOrdersf);
			}
			if(processWorkOrdersd != null){
				processWorkOrders.addAll(processWorkOrdersd);
			}
			if(processWorkOrderse != null){
				processWorkOrders.addAll(processWorkOrderse);
			}
		}else {
			switch (processWorkOrder.getStatus()) {
				/**
				 * 未处理
				 */
				case 1:
					processWorkOrders = listBladeFlowResultd(listBladeFlow, query, list,processWorkOrder);
					break;
				/**
				 * 处理中
				 */
				case 2:
					processWorkOrders = listBladeFlowResult(listBladeFlow, query, list,processWorkOrder);
					break;
				/**
				 * 处理完
				 */
				case 3:
					processWorkOrders = listBladeFlowResulte(listBladeFlow, query, list,processWorkOrder);
					break;
				default:
			}
		}
		return page.setRecords(processWorkOrders);
	}
	private List<ProcessWorkOrder> listBladeFlowResult(List<BladeFlow> listBladeFlow,Query query,List<String> list,ProcessWorkOrder processWorkOrder){
		BladePage<BladeFlow> result = flowClient.sendList(query.getCurrent(),query.getSize());
		listBladeFlow =  result.getRecords();
		listBladeFlow.forEach(b->{
			list.add(b.getProcessInstanceId());
		});
		if(listBladeFlow == null || listBladeFlow.size()==0){
			return null;
		}
		IPage<ProcessWorkOrder> page = Condition.getPage(query);
		return queryProcessWorkOrders(listBladeFlow,list,processWorkOrder,page);
	}
	private List<ProcessWorkOrder> listBladeFlowResultd(List<BladeFlow> listBladeFlow,Query query,List<String> list,ProcessWorkOrder processWorkOrder){
		BladePage<BladeFlow> resultd = flowClient.todoList(query.getCurrent(),query.getSize());
		if(resultd == null) return null;
		listBladeFlow =  resultd.getRecords();
		listBladeFlow.forEach(b->{
			list.add(b.getProcessInstanceId());
		});
		if(listBladeFlow == null || listBladeFlow.size()==0){
			return null;
		}
		IPage<ProcessWorkOrder> page = Condition.getPage(query);
		return queryProcessWorkOrders(listBladeFlow,list,processWorkOrder,page);
	}
	private List<ProcessWorkOrder> listBladeFlowResulte(List<BladeFlow> listBladeFlow,Query query,List<String> list,ProcessWorkOrder processWorkOrder){
		BladePage<BladeFlow> resulte = flowClient.doneList(query.getCurrent(),query.getSize());
			listBladeFlow =  resulte.getRecords();
		if(resulte == null) return null;
		listBladeFlow.forEach(b->{
			list.add(b.getProcessInstanceId());
		});
		if(listBladeFlow == null || listBladeFlow.size()==0){
			return null;
		}
		IPage<ProcessWorkOrder> page = Condition.getPage(query);
		return queryProcessWorkOrders(listBladeFlow,list,processWorkOrder,page);
	}
	private List<ProcessWorkOrder> queryProcessWorkOrders(List<BladeFlow> listBladeFlow,List<String> list,ProcessWorkOrder processWorkOrder,IPage<ProcessWorkOrder> page){
		List<ProcessWorkOrder> processWorkOrders = baseMapper.selectWorkOrderPage(page,processWorkOrder,list);
		AtomicBoolean temp = new AtomicBoolean(false);
		processWorkOrders.forEach(v->{
			listBladeFlow.forEach(n->{
				if(v.getProcessInstanceId().equals(n.getProcessInstanceId())){
					v.setFlow(n);
					temp.set(true);
				}
			});
		});
		if(!temp.get()){
			return null;
		}
		return processWorkOrders;
	}


}
